package com.socket.server.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * @author wangg
 * @date 2019/4/12 10:46
 */
public class NIOSocketServer implements Runnable {

    /**
     * 多路复用器（管理所有socket的通道）
     */
    private Selector selector;
    /**
     * 建立缓冲区 8KB
     */
    private ByteBuffer readBuffer = ByteBuffer.allocateDirect(200);
    private ByteBuffer writeBuffer = ByteBuffer.allocateDirect(1024 * 8);


    public NIOSocketServer(int port) {
        try {
            //打开多路复用
            this.selector = Selector.open();
            //打开服务端socket通道
            ServerSocketChannel socketChannel = ServerSocketChannel.open();
            //设置服务端通道为非阻塞模式
            socketChannel.configureBlocking(false);
            //绑定服务端端口
            socketChannel.bind(new InetSocketAddress(port));
            //把服务端socket通道注册到多路复用器上，并且监听阻塞事件
            socketChannel.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new Thread(new NIOSocketServer(80)).start();
    }

    private void read(SelectionKey key) {
        try {
            this.readBuffer.clear();
            SocketChannel socketChannel = (SocketChannel) key.channel();
            int count = socketChannel.read(this.readBuffer);
            if (count == -1) {
                key.channel().close();
                key.cancel();
                return;
            }
            this.readBuffer.flip();
            byte[] bytes = new byte[this.readBuffer.remaining()];
            this.readBuffer.get(bytes);
            System.out.println(new String(bytes));
        } catch (IOException e) {
            e.printStackTrace();
        }


    }

    private void accept(SelectionKey key) {
        try {
            ServerSocketChannel sSocketChannel = (ServerSocketChannel) key.channel();
            SocketChannel channel = sSocketChannel.accept();
            channel.configureBlocking(false);
            channel.register(this.selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private void write(SelectionKey key){
        try {
            SocketChannel socketChannel = (SocketChannel) key.channel();
            int count = socketChannel.write(readBuffer);
            if (count == -1) {
                key.channel().close();
                key.cancel();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        try {
            // this.selector.select()
            while (this.selector.select() > 0) {
                Iterator<SelectionKey> keys = this.selector.selectedKeys().iterator();
                while (keys.hasNext()) {
                    SelectionKey key = keys.next();
                    if (key.isValid()) {
                        if (key.isAcceptable()) {
                            this.accept(key);
                        } else if (key.isReadable()) {
                            this.read(key);
                        }
                    }
                    keys.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
